const doctrine = require('doctrine');
const { declare } = require("@babel/helper-plugin-utils");

/** 类型转换 */
function resolveType(tsType) {
  const typeAnnotation = tsType.typeAnnotation;
  if (!typeAnnotation) {
      return;
  }
  switch (typeAnnotation.type) {
      case 'TSStringKeyword': 
          return 'string';
      case 'TSNumberKeyword':
          return 'number';
      case 'TSBooleanKeyword':
          return 'boolean';
  }
}

/** 解析注释 */
function parseComment(commentStr) {
  if (!commentStr) {
    return;
  }
  return doctrine.parse(commentStr, {
      unwrap: true
  });
}

const autoDocumentPlugin = declare((api, options, dirname) => {
  api.assertVersion(7);
  return {
    pre(file) {
      // 全局变量，信息收集
      file.set("docs", [])
    },
    visitor: {
      FunctionDeclaration(path, state) {
        const docs = state.file.get("docs");
        docs.push({
          // 类型
          type: "function",
          // 函数名称
          name: path.get("id").toString(),
          // 函数参数
          params: path.get("params").map(paramPath => {
            return {
              name: paramPath.toString(),
              type: resolveType(paramPath.getTypeAnnotation())
            }
          }),
          // 函数返回值
          return: resolveType(path.get("returnType").getTypeAnnotation()),
          // 注释说明
          doc: path.node.leadingComments  && parseComment(path.node.leadingComments[0].value)
        });
        state.file.set("docs", docs);
      },
      ClassDeclaration(path, state) {
        const docs = state.file.get('docs');
        const classInfo = {
            type: 'class',
            name: path.get('id').toString(),
            // constructor
            constructorInfo: {},
            // method 属性
            methodsInfo: [],
            // 原型属性
            propertiesInfo: []
        };
        if (path.node.leadingComments) {
            classInfo.doc = parseComment(path.node.leadingComments[0].value);
        }
        path.traverse({
          ClassProperty(path) {
              classInfo.propertiesInfo.push({
                  name: path.get('key').toString(),
                  type: resolveType(path.getTypeAnnotation()),
                  doc: [path.node.leadingComments, path.node.trailingComments].filter(Boolean).map(comment => {
                      return parseComment(comment.value);
                  }).filter(Boolean)
              })
          },
          ClassMethod(path) {
              if (path.node.kind === 'constructor') {
                  classInfo.constructorInfo = {
                      params: path.get('params').map(paramPath=> {
                          return {
                              name: paramPath.toString(),
                              type: resolveType(paramPath.getTypeAnnotation()),
                              doc: parseComment(path.node.leadingComments[0].value)
                          }
                      })
                  }
              } else {
                  classInfo.methodsInfo.push({
                      name: path.get('key').toString(),
                      doc: parseComment(path.node.leadingComments[0].value),
                      params: path.get('params').map(paramPath=> {
                          return {
                              name: paramPath.toString(),
                              type: resolveType(paramPath.getTypeAnnotation())
                          }
                      }),
                      return: resolveType(path.getTypeAnnotation())
                  })
              }
          }
      });
        docs.push(classInfo);
        state.file.set('docs', docs);
      }
    },
    post(file) {
      const docs = file.get("docs")
      // 生成文档
    }
  }
})

module.exports = autoDocumentPlugin;
